// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 软件包cpu实现处理器功能检测
// 由Go标准库使用。
package cpu

// 如果操作系统支持在运行时启动早期读取
// GODEBUG，则运行时会将DebugOptions设置为true。
// 初始化后不应更改。
var DebugOptions bool

// CacheLinePad用于填充结构以避免错误共享。
type CacheLinePad struct{ _ [CacheLinePadSize]byte }

// CacheLineSize是CPU假定的缓存线大小。
// 目前没有实际缓存线大小的运行时检测
// 因此我们使用每GOARCH CacheLinePadSize的常数作为近似值。
var CacheLineSize uintptr = CacheLinePadSize

// X86中的布尔值包含相应命名的cpuid特征位。
// 仅当操作系统支持XMM和YMM寄存器
// 以及正在设置的cpuid功能位时，才设置HasAVX和HasAVX2。
// 结构被填充以避免错误共享。
var X86 struct {
	_            CacheLinePad
	HasAES       bool
	HasADX       bool
	HasAVX       bool
	HasAVX2      bool
	HasBMI1      bool
	HasBMI2      bool
	HasERMS      bool
	HasFMA       bool
	HasOSXSAVE   bool
	HasPCLMULQDQ bool
	HasPOPCNT    bool
	HasRDTSCP    bool
	HasSSE3      bool
	HasSSSE3     bool
	HasSSE41     bool
	HasSSE42     bool
	_            CacheLinePad
}

// ARM中的布尔值包含相应命名的cpu特征位。
// 结构被填充以避免错误共享。
var ARM struct {
	_        CacheLinePad
	HasVFPv4 bool
	HasIDIVA bool
	_        CacheLinePad
}

// ARM64中的布尔值包含相应命名的cpu功能位。
// 结构被填充以避免错误共享。
var ARM64 struct {
	_            CacheLinePad
	HasAES       bool
	HasPMULL     bool
	HasSHA1      bool
	HasSHA2      bool
	HasCRC32     bool
	HasATOMICS   bool
	HasCPUID     bool
	IsNeoverseN1 bool
	IsZeus       bool
	_            CacheLinePad
}

var MIPS64X struct {
	_      CacheLinePad
	HasMSA bool // MIPS SIMD架构
	_      CacheLinePad
}

// 对于ppc64（le），只检查从ISA v3开始的ISA级别是安全的。00，
// 因为没有可选类别。也有一些例外情况需要内核支持才能工作（darn，scv），因此
// 也有一些功能位。处理器的最低要求是POWER8（ISA 2.07）。
// 结构被填充以避免错误共享。
var PPC64 struct {
	_        CacheLinePad
	HasDARN  bool // 硬件随机数生成器（需要启用内核）
	HasSCV   bool // 系统调用向量化（需要启用内核）
	IsPOWER8 bool // ISA v2。07（POWER8）
	IsPOWER9 bool // ISA v3。00（POWER9）
	_        CacheLinePad
}

var S390X struct {
	_         CacheLinePad
	HasZARCH  bool // z体系结构模式处于活动状态[必需]
	HasSTFLE  bool // 存储设备列表扩展[必需]
	HasLDISP  bool // 长（20位）位移[必需]
	HasEIMM   bool // 32位即时[必需]
	HasDFP    bool // 十进制浮点
	HasETF3EH bool // ETF-3增强型
	HasMSA    bool // 消息安全辅助（CPACF）
	HasAES    bool // KMC-AES{128192256}函数
	HasAESCBC bool // KMC-AES{128192256}函数
	HasAESCTR bool // KMCTR-AES{128192256}函数
	HasAESGCM bool // KMA-GCM-AES{128192256}函数
	HasGHASH  bool // KIMD-GHASH函数
	HasSHA1   bool // K{I，L}MD-SHA-1函数
	HasSHA256 bool // K{I，L-MD-MD-MD-128}函数
	HasSHA3   bool // K{I，L}MD-SHA3-{224256384512}和K{I，L}MD-SHAKE-{128256}函数
	HasVX     bool // vector facility。注意：运行时在处理auxv记录时设置此选项。
	HasVXE    bool // 矢量增强功能1 
	HasKDSA   bool // 椭圆曲线函数
	HasECDSA  bool // NIST曲线
	HasEDDSA  bool // 爱德华兹曲线
	_         CacheLinePad
}

// 初始化检查处理器并设置上述相关变量。
// 这是在程序初始化的早期由运行时包调用的，
// 在正常的初始化函数运行之前。如果操作系统支持GODEBUG中的
// cpu功能选项，则env由运行时设置。
func Initialize(env string) {
	doinit()
	processOptions(env)
}

// 选项包含可在GODEBUG中使用的cpu调试选项。
// 选项依赖于arch，由arch特定的doinit函数添加。
// 不应将特定目标所必需的功能添加到选项
// （例如amd64上的SSE2）。
var options []option

// 选项名称应为小写。e、 g.avx而不是avx。
type option struct {
	Name      string
	Feature   *bool
	Specified bool // 是否在GODEBUG中指定了功能值
	Enable    bool // 是否应启用功能
}

// processOptions根据解析的环境字符串启用或禁用CPU功能值。
// 环境字符串的格式应为cpu。功能1=值1，cpu。功能2=价值2。。。
// 其中功能名称是存储在
// cpu包选项变量中的特定于体系结构的列表之一，值为“开”或“关”。
// 如果env包含cpu。all=off则通过选项
// 变量引用的所有cpu功能都被禁用。其他功能名称和值会产生警告消息。
func processOptions(env string) {
field:
	for env != "" {
		field := ""
		i := indexByte(env, ',')
		if i < 0 {
			field, env = env, ""
		} else {
			field, env = env[:i], env[i+1:]
		}
		if len(field) < 4 || field[:4] != "cpu." {
			continue
		}
		i = indexByte(field, '=')
		if i < 0 {
			print("GODEBUG: no value specified for \"", field, "\"\n")
			continue
		}
		key, value := field[4:i], field[i+1:] // 例如“SSE2”，“on”

		var enable bool
		switch value {
		case "on":
			enable = true
		case "off":
			enable = false
		default:
			print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
			continue field
		}

		if key == "all" {
			for i := range options {
				options[i].Specified = true
				options[i].Enable = enable
			}
			continue field
		}

		for i := range options {
			if options[i].Name == key {
				options[i].Specified = true
				options[i].Enable = enable
				continue field
			}
		}

		print("GODEBUG: unknown cpu feature \"", key, "\"\n")
	}

	for _, o := range options {
		if !o.Specified {
			continue
		}

		if o.Enable && !*o.Feature {
			print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n")
			continue
		}

		*o.Feature = o.Enable
	}
}

// indexByte返回s中c的第一个实例的索引，如果s中不存在c，则返回-1
func indexByte(s string, c byte) int {
	for i := 0; i < len(s); i++ {
		if s[i] == c {
			return i
		}
	}
	return -1
}
